import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer';

import {
  append as svgAppend,
  attr as svgAttr,
  create as svgCreate,
  remove as svgRemove,
  clear as clearChildren,
  classes as svgClasses,
  select as selectNode,
  selectAll as selectNodeAll
} from 'tiny-svg';

import {
  getRoundRectPath
} from 'bpmn-js/lib/draw/BpmnRenderUtil';
import {isFrameElement} from 'diagram-js/lib/util/Elements';
import {getBusinessObject, is} from 'bpmn-js/lib/util/ModelUtil';
import { isAny } from 'bpmn-js/lib/features/modeling/util/ModelingUtil';
import businessConfig from "@/components/business/config";
import {STYLE_CONFIG} from './BisDesignStyle';

const HIGH_PRIORITY = 1500,
      TASK_BORDER_RADIUS = 10;


export default class CustomBisRenderer extends BaseRenderer {
  constructor(eventBus, bpmnRenderer,styles,canvas) {
    super(eventBus, HIGH_PRIORITY);
    this.canvas = canvas
    this.bpmnRenderer = bpmnRenderer;
    this.STYLE_CONFIG = STYLE_CONFIG;
    this.eventBus = eventBus;
    this.styles = styles;
    this.bpmnRenderer = bpmnRenderer;
    // 当前需要高亮的ID,已经提示的文字,status = complete完成，active激活（正在办理）,pending挂起（不可办理）
    this.highlight = {}
  }

  setHighlight(ids){
    this.highlight = ids || {};
  }

  setTooltip(tooltip){
    this.tooltip = tooltip;
  }
  canRender(element) {
    return true;
  }
  getStyle(element,isLine){
    const id = element.id
    const config = this.highlight[id]?this.highlight[id][0]:{status:'default'}
    config.status = config.status.toLowerCase()
    const styleConfig = this.STYLE_CONFIG[config.status];
    let style = {}
    if(isLine){
      style = styleConfig.connection
      element.di.set('fill',style['fill'])
      element.di.set('stroke',style['stroke'])
    }else{
      // 线上文字的样式
      if(element.type=='label'){
        style = styleConfig.label;
        return style;
      }
      style = isFrameElement(element)?styleConfig.frame:styleConfig.shape;
      // 回调鼠标悬停事件
      if(config.tipTitle&&this.tooltip){
        this.eventBus.on('element.hover', (e)=>{
          if(e.element==element){
            this.tooltip.call(this,element,e,config.nodeId,true)
          }
        });
        this.eventBus.on('element.out', (e)=>{
          if(e.element==element){
            this.tooltip.call(this,element,e,config.nodeId,false)
          }
        });
      }
    }
    if(config.status){
      this.canvas.addMarker(element, 'hp-highlight-'+config.status)
    }
    return style;
  }

  drawConnection(visuals, connection, attrs) {
    let businessObject = connection.businessObject;
    let targetRef = businessObject.get("targetRef");
    if(targetRef){
      // 目标元素的状态
      const config = this.highlight[targetRef]?this.highlight[targetRef][0]:{status:'default'}
      // 线跟着目标元素走
      this.highlight[connection.id] = this.highlight[connection.id]||[]
      if(this.highlight[connection.id].length==0){
        this.highlight[connection.id].push({
          status: config['status'].toLowerCase()
        })
      }
    }

    let style = this.getStyle(connection,true);
    const line = this.bpmnRenderer.drawConnection(visuals, connection, attrs);
    svgAttr(line, style);
    return line;
  }

  drawShape(pNode, element) {
    const shape = this.bpmnRenderer.drawShape(pNode, element);
    if (is(element, 'bpmn:UserTask')) {
      svgRemove(shape);
      clearChildren(pNode)
      const width = 200,height=40;
      const hissType = element.businessObject.get('hissType')
      const hissColor = element.businessObject.get('hissColor')
      let fun = this[hissType+"Icon"];
      if(fun){
        let icon = fun.call(this,element,pNode,5,2,'#fff')
        prependTo(icon, pNode);
      }
      const hissConf = businessConfig[hissType]
      let hissTypeName = element.businessObject.get('hissTypeName')
      if(hissConf&&hissConf.bindTitleField){
        // let tempValue = getFieldValue(element.businessObject,hissConf.bindTitleField)
        let tempValue;
        let windowConfig = window['bisConfig'];
        if(windowConfig){
          let config = windowConfig();
          let nodeConfigElement = config.nodeConfig[element.businessObject.get('id')];
          if(nodeConfigElement){
            tempValue=nodeConfigElement[hissConf.bindTitleField]
          }
        }
        let translate = window['translate']||element['translate']
        if(tempValue&&translate){
          tempValue = hissTypeName+": "+translate(tempValue+"Node")
        }
        hissTypeName = tempValue||hissTypeName
      }
      const rectTitle = drawRect(pNode, width, height, TASK_BORDER_RADIUS, hissColor,0,0);
      const rectBoby = drawRect(pNode, width, height, TASK_BORDER_RADIUS, '#f8f8f8',0,40);
      const rectCover = drawRect(pNode, width, height, 0, '#f8f8f8',0,30);
      const typeText = drawText(pNode,30,20,hissTypeName,'#fff')
      let name = element.businessObject.get('name')
      let y = 50
      if(name && name.length<=10){
        y += 8;
      }
      const nameText = drawText(pNode,18,y, name,'#666')
      prependTo(typeText, pNode);
      prependTo(nameText, pNode);
      prependTo(rectCover, pNode);
      prependTo(rectTitle, pNode);
      prependTo(rectBoby, pNode);
      const config = this.highlight[element.id]?this.highlight[element.id][0]:{status:'default'}
      config.status = config.status.toLowerCase()
      if(config.status!='default'&&config.status!='active'){
        svgAttr(rectTitle, this.getStyle(element,false));
      }
      svgAttr(shape, this.getStyle(element,false));
      return shape;
    }

    const rect = drawRect(pNode, 30, 20, TASK_BORDER_RADIUS, '#cc0000');

    svgAttr(rect, {
      transform: 'translate(-20, -10)'
    });
    return shape;
  }



  starterIcon(element,parentNode, x, y,color) {
    const svg = svgCreate('svg');
    svgAttr(svg, {
      x: x,
      y: y,
      width:24,
      height:24,
      fill:'none',
      stroke: color ||'#3537af',
      'stroke-width':2,
      'stroke-linecap':'round',
      'stroke-linejoin':'round'
    });
    const path = drawPath(svg,{
      d: 'M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2'
    });
    const circle =drawCircle(svg,{
      cx:12,
      cy:7,
      r:4
    });
    svgAppend(parentNode, svg);
    svgAppend(svg, path);
    svgAppend(svg, circle);
    return svg;
  }

  conditionIcon(element,parentNode, x, y,color) {
    const svg = svgCreate('svg');
    svgAttr(svg, {
      x: x,
      y: y,
      width:24,
      height:24,
      fill:'none',
      stroke: color ||'#3537af',
      'stroke-width':2,
      'stroke-linecap':'round',
      'stroke-linejoin':'round'
    });
    const circle1 =drawCircle(svg,{
      cx:12,
      cy:18,
      r:3
    });
    const circle2 =drawCircle(svg,{
      cx:6,
      cy:6,
      r:3
    });
    const circle3 =drawCircle(svg,{
      cx:18,
      cy:6,
      r:3
    });
    const path1 = drawPath(svg,{
      d: 'M18 9v1a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V9'
    });
    const path2 = drawPath(svg,{
      d: 'M12 12v3'
    });
    svgAppend(parentNode, svg);
    svgAppend(svg, circle1);
    svgAppend(svg, circle2);
    svgAppend(svg, circle3);
    svgAppend(svg, path1);
    svgAppend(svg, path2);
    return svg;
  }

  singleApproveIcon(element,parentNode, x, y,color) {
    const svg = svgCreate('svg');
    svgAttr(svg, {
      x: x,
      y: y,
      width:24,
      height:24,
      fill:'none',
      stroke: color ||'#3537af',
      'stroke-width':2,
      'stroke-linecap':'round',
      'stroke-linejoin':'round'
    });
    const line1 = drawLine(svg,17,5,23,5)
    const path1 = drawPath(svg,{
      d: 'M5 22h14'
    });
    const path2 = drawPath(svg,{
      d: 'M19.27 13.73A2.5 2.5 0 0 0 17.5 13h-11A2.5 2.5 0 0 0 4 15.5V17a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-1.5c0-.66-.26-1.3-.73-1.77Z'
    });
    const path3 = drawPath(svg,{
      d: 'M14 13V8.5C14 7 15 7 15 5a3 3 0 0 0-3-3c-1.66 0-3 1-3 3s1 2 1 3.5V13'
    });
    svgAppend(parentNode, svg);
    svgAppend(svg, line1);
    svgAppend(svg, path1);
    svgAppend(svg, path2);
    svgAppend(svg, path3);
    return svg;
  }

  multipleApproveIcon(element,parentNode, x, y,color) {
    const svg = svgCreate('svg');
    svgAttr(svg, {
      x: x,
      y: y,
      width:24,
      height:24,
      fill:'none',
      stroke: color ||'#3537af',
      'stroke-width':2,
      'stroke-linecap':'round',
      'stroke-linejoin':'round'
    });
    const line1 = drawLine(svg,17,5,23,5)
    const line2 = drawLine(svg,20,2,20,8)
    const path1 = drawPath(svg,{
      d: 'M5 22h14'
    });
    const path2 = drawPath(svg,{
      d: 'M19.27 13.73A2.5 2.5 0 0 0 17.5 13h-11A2.5 2.5 0 0 0 4 15.5V17a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-1.5c0-.66-.26-1.3-.73-1.77Z'
    });
    const path3 = drawPath(svg,{
      d: 'M14 13V8.5C14 7 15 7 15 5a3 3 0 0 0-3-3c-1.66 0-3 1-3 3s1 2 1 3.5V13'
    });
    svgAppend(parentNode, svg);
    svgAppend(svg, line1);
    svgAppend(svg, line2);
    svgAppend(svg, path1);
    svgAppend(svg, path2);
    svgAppend(svg, path3);
    return svg;
  }

  notifierIcon(element,parentNode, x, y,color) {
    const svg = svgCreate('svg');
    svgAttr(svg, {
      x: x,
      y: y,
      width:24,
      height:24,
      fill:'none',
      stroke: color ||'#3537af',
      'stroke-width':2,
      'stroke-linecap':'round',
      'stroke-linejoin':'round'
    });
    const path1 = drawPath(svg,{
      d: 'm15.50725,3.50725a3.0139,3.0139 0 0 1 0,2.9855'
    });
    const path2 = drawPath(svg,{
      d: 'm18.80783,1.77461a6.1687,6.55106 0 0 1 0,6.45079'
    });
    const path3 = drawPath(svg,{
      d: 'm22.1129,0.90748a8.24202,8.24202 0 0 1 0.00518,8.18503'
    });
    const path4 = drawPath(svg,{
      d: 'M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2'
    });
    const circle =drawCircle(svg,{
      cx:12,
      cy:7,
      r:4
    });
    svgAppend(parentNode, svg);
    svgAppend(svg, circle);
    svgAppend(svg, path1);
    svgAppend(svg, path2);
    svgAppend(svg, path3);
    svgAppend(svg, path4);
    return svg;
  }

  ccIcon(element,parentNode, x, y,color) {
    const svg = svgCreate('svg');
    svgAttr(svg, {
      x: x,
      y: y,
      width:24,
      height:24,
      fill:'none',
      stroke: color ||'#3537af',
      'stroke-width':2,
      'stroke-linecap':'round',
      'stroke-linejoin':'round'
    });
    const polygon = drawPolygon(svg,{
      points: '3 11 22 2 13 21 11 13 3 11'
    });
    svgAppend(parentNode, svg);
    svgAppend(svg, polygon);
    return svg;
  }

}

CustomBisRenderer.$inject = [ 'eventBus','bpmnRenderer', 'styles','canvas'];
// helpers //////////
function drawLine(parentNode,x1,y1,x2,y2) {
  const line = svgCreate('line');
  svgAttr(line, {
    x2: x2,
    y2: y2,
    x1: x1,
    y1: y1
  });
  svgAppend(parentNode, line);
  return line;
}

function drawPolygon(parentNode,points) {
  const polygon = svgCreate('polygon');
  svgAttr(polygon, {points});
  svgAppend(parentNode, polygon);
  return polygon;
}


function drawRect(parentNode, width, height, borderRadius, strokeColor,x,y) {
  const rect = svgCreate('rect');
  svgAttr(rect, {
    width: width,
    height: height,
    rx: borderRadius,
    ry: borderRadius,
    x: x,
    y: y,
    viewBox:"0 0 24 24",
    stroke: strokeColor || '#000',
    strokeWidth: 2,
    fill: strokeColor||'#fff'
  });

  svgAppend(parentNode, rect);

  return rect;
}

function drawText(parentNode, x, y,content,color) {
  const text = svgCreate('text');
  svgAttr(text, {
    x: x,
    y: y,
    class:'task-title',
    fill: color ||'#3537af',
  });
  svgAppend(parentNode, text);
  let tempY = y
  if(content) {
    if(content.length>20){
      content = content.substring(0, 20)
    }
    while (content.length > 10) {
      const temp = content.substring(0, 10)
      content = content.substring(10)
      drawTspan(text, x, tempY, temp)
      tempY = tempY + 20
    }
    if (content.length > 0) {
      drawTspan(text, x, tempY, content)
    }
  }
  // text.textContent=content
  return text;
}

function drawTspan(text,x,y,content){
  const tspan = svgCreate('tspan');
  svgAppend(text, tspan);
  svgAttr(tspan, {
    x:x, y: y
  });
  tspan.textContent = content
}

function drawCircle(parentNode,attr){
  const circle = svgCreate('circle');
  svgAttr(circle, attr);
  svgAppend(parentNode, circle);
  return circle;
}

function drawPath(parentNode,attr){
  const path = svgCreate('path');
  svgAttr(path, attr);
  svgAppend(parentNode, path);
  return path;
}

function prependTo(newNode, parentNode, siblingNode) {
  parentNode.insertBefore(newNode, siblingNode || parentNode.firstChild);
}

function getExtensionElementsAndName(businessObject, type = undefined,name = undefined) {
  if(businessObject==undefined){
    return [];
  }
  const extensionElements = businessObject.get('extensionElements');
  if (!extensionElements) {
    return [];
  }
  let values = extensionElements.get('values');
  if (!values || !values.length) {
    return [];
  }
  if (type) {
    values = values.filter(value => is(value, type));
  }
  if(name) {
    values = values.filter(value => value.get('name')==name);
  }
  return values;
}

function getFieldValue(businessObject,filedName){
  let extensionElementsTo = getExtensionElementsAndName(businessObject,'activiti:Field',filedName);
  let field;
  if(extensionElementsTo&&extensionElementsTo.length){
    field = extensionElementsTo[0]
  }
  if(field) {
    return  field.string || field.stringValue || field.expression;
  }
  return ''
}
